﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Rex.BaseService.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;

namespace Rex.BaseService.Systems.UserOrganizationUnits
{
    /// <summary>
    /// 组织单元【用户】仓储
    /// </summary>
    [Dependency(ServiceLifetime.Singleton)]
    public class UserOrganizationUnitRepository : EfCoreRepository<BaseServiceDbContext, IdentityUserOrganizationUnit>, IUserOrganizationUnitRepository
    {
        public IIdentityUserRepository IdentityUserRepository { get; set; }

        public UserOrganizationUnitRepository(IDbContextProvider<BaseServiceDbContext> dbContextProvider) : base(dbContextProvider)
        {
        }

        /// <summary>
        /// 获取组织单元【用户】信息
        /// </summary>
        /// <param name="filter">过滤筛选</param>
        /// <param name="maxResultCount">查询数量</param>
        /// <param name="skipCount">跳过数</param>
        /// <param name="organizationUnitId">组织单元ID</param>
        /// <param name="sorting">排序</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<List<IdentityUserOrganizationUnit>> GetListAsync(string? filter, int maxResultCount, int skipCount, Guid? organizationUnitId = null, string sorting = null, CancellationToken cancellationToken = default)
        {
            IdentityUser identityUser = null;
            if (!string.IsNullOrWhiteSpace(filter))
            {
                identityUser = await IdentityUserRepository.FindByNormalizedUserNameAsync(filter);
            }
            if (!string.IsNullOrWhiteSpace(filter) && identityUser == null)
            {
                return new List<IdentityUserOrganizationUnit>();
            }

            List<IdentityUserOrganizationUnit> uOuList = await (await GetDbSetAsync())
                .WhereIf(identityUser != null, u => u.UserId == identityUser.Id)
                .WhereIf(organizationUnitId != null, u => u.OrganizationUnitId == organizationUnitId.Value)
                .OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(IdentityUserOrganizationUnit.UserId) : sorting)
                .PageBy(skipCount, maxResultCount)
                .ToListAsync(GetCancellationToken(cancellationToken));

            return uOuList;
        }

        /// <summary>
        /// 获取组织单元【用户】信息数量
        /// </summary>
        /// <param name="filter">过滤筛选</param>
        /// <param name="organizationUnitId">组织单元ID</param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<long> GetListCountAsync(string? filter, Guid? organizationUnitId = null, CancellationToken cancellationToken = default)
        {
            IdentityUser identityUser = null;
            if (!string.IsNullOrWhiteSpace(filter))
            {
                identityUser = await IdentityUserRepository.FindByNormalizedUserNameAsync(filter);
            }
            if (!string.IsNullOrWhiteSpace(filter) && identityUser == null)
            {
                return 0;
            }

            return await (await GetDbSetAsync())
                .WhereIf(identityUser != null, u => u.UserId == identityUser.Id)
                .WhereIf(organizationUnitId != null, u => u.OrganizationUnitId == organizationUnitId.Value)
                .LongCountAsync(GetCancellationToken(cancellationToken));
        }

        /// <summary>
        /// 选择组织单元用户
        /// </summary>
        /// <returns></returns>
        public async Task<List<IdentityUser>> GetSelectUserListAsync(List<Guid> notUserIds = null, string sorting = null, int maxResultCount = int.MaxValue, int skipCount = 0, string filter = null, bool includeDetails = false, Guid? roleId = null, Guid? organizationUnitId = null, string userName = null, string phoneNumber = null, string emailAddress = null, string name = null, string surname = null, bool? isLockedOut = null, bool? notActive = null, bool? emailConfirmed = null, bool? isExternal = null, DateTime? maxCreationTime = null, DateTime? minCreationTime = null, DateTime? maxModifitionTime = null, DateTime? minModifitionTime = null, CancellationToken cancellationToken = default)
        {
            return await (await IdentityUserRepository.GetDbSetAsync())
            .IncludeDetails(includeDetails)
            .WhereIf(
                !filter.IsNullOrWhiteSpace(),
                u =>
                    u.UserName.Contains(filter) ||
                    u.Email.Contains(filter) ||
                    (u.Name != null && u.Name.Contains(filter)) ||
                    (u.Surname != null && u.Surname.Contains(filter)) ||
                    (u.PhoneNumber != null && u.PhoneNumber.Contains(filter))
            )
            .WhereIf((notUserIds != null && notUserIds.Count > 0), u => !notUserIds.Contains(u.Id))
            .WhereIf(roleId.HasValue, identityUser => identityUser.Roles.Any(x => x.RoleId == roleId.Value))
            .WhereIf(organizationUnitId.HasValue, identityUser => identityUser.OrganizationUnits.Any(x => x.OrganizationUnitId == organizationUnitId.Value))
            .WhereIf(!string.IsNullOrWhiteSpace(userName), x => x.UserName == userName)
            .WhereIf(!string.IsNullOrWhiteSpace(phoneNumber), x => x.PhoneNumber == phoneNumber)
            .WhereIf(!string.IsNullOrWhiteSpace(emailAddress), x => x.Email == emailAddress)
            .WhereIf(!string.IsNullOrWhiteSpace(name), x => x.Name == name)
            .WhereIf(!string.IsNullOrWhiteSpace(surname), x => x.Surname == surname)
            .WhereIf(isLockedOut.HasValue, x => (x.LockoutEnabled && x.LockoutEnd.HasValue && x.LockoutEnd.Value.CompareTo(DateTime.UtcNow) > 0) == isLockedOut.Value)
            .WhereIf(notActive.HasValue, x => x.IsActive == !notActive.Value)
            .WhereIf(emailConfirmed.HasValue, x => x.EmailConfirmed == emailConfirmed.Value)
            .WhereIf(isExternal.HasValue, x => x.IsExternal == isExternal.Value)
            .WhereIf(maxCreationTime != null, p => p.CreationTime <= maxCreationTime)
            .WhereIf(minCreationTime != null, p => p.CreationTime >= minCreationTime)
            .WhereIf(maxModifitionTime != null, p => p.LastModificationTime <= maxModifitionTime)
            .WhereIf(minModifitionTime != null, p => p.LastModificationTime >= minModifitionTime)
            .OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(IdentityUser.UserName) : sorting)
            .PageBy(skipCount, maxResultCount)
            .ToListAsync(GetCancellationToken(cancellationToken));
        }

        /// <summary>
        /// 选择组织单元用户数量
        /// </summary>
        /// <returns></returns>
        public async Task<long> GetSelectUserCountAsync(List<Guid> notUserIds = null, string filter = null, Guid? roleId = null, Guid? organizationUnitId = null, string userName = null, string phoneNumber = null, string emailAddress = null, string name = null, string surname = null, bool? isLockedOut = null, bool? notActive = null, bool? emailConfirmed = null, bool? isExternal = null, DateTime? maxCreationTime = null, DateTime? minCreationTime = null, DateTime? maxModifitionTime = null, DateTime? minModifitionTime = null, CancellationToken cancellationToken = default)
        {
            return await (await IdentityUserRepository.GetDbSetAsync())
            .WhereIf(
                !filter.IsNullOrWhiteSpace(),
                u =>
                    u.UserName.Contains(filter) ||
                    u.Email.Contains(filter) ||
                    (u.Name != null && u.Name.Contains(filter)) ||
                    (u.Surname != null && u.Surname.Contains(filter)) ||
                    (u.PhoneNumber != null && u.PhoneNumber.Contains(filter))
            )
            .WhereIf((notUserIds != null && notUserIds.Count > 0), u => !notUserIds.Contains(u.Id))
            .WhereIf(roleId.HasValue, identityUser => identityUser.Roles.Any(x => x.RoleId == roleId.Value))
            .WhereIf(organizationUnitId.HasValue, identityUser => identityUser.OrganizationUnits.Any(p => p.OrganizationUnitId == organizationUnitId.Value))
            .WhereIf(!string.IsNullOrWhiteSpace(userName), x => x.UserName == userName)
            .WhereIf(!string.IsNullOrWhiteSpace(phoneNumber), x => x.PhoneNumber == phoneNumber)
            .WhereIf(!string.IsNullOrWhiteSpace(emailAddress), x => x.Email == emailAddress)
            .WhereIf(!string.IsNullOrWhiteSpace(name), x => x.Name == name)
            .WhereIf(!string.IsNullOrWhiteSpace(surname), x => x.Surname == surname)
            .WhereIf(isLockedOut.HasValue, x => (x.LockoutEnabled && x.LockoutEnd.HasValue && x.LockoutEnd.Value.CompareTo(DateTime.UtcNow) > 0) == isLockedOut.Value)
            .WhereIf(notActive.HasValue, x => x.IsActive == !notActive.Value)
            .WhereIf(emailConfirmed.HasValue, x => x.EmailConfirmed == emailConfirmed.Value)
            .WhereIf(isExternal.HasValue, x => x.IsExternal == isExternal.Value)
            .WhereIf(maxCreationTime != null, p => p.CreationTime <= maxCreationTime)
            .WhereIf(minCreationTime != null, p => p.CreationTime >= minCreationTime)
            .WhereIf(maxModifitionTime != null, p => p.LastModificationTime <= maxModifitionTime)
            .WhereIf(minModifitionTime != null, p => p.LastModificationTime >= minModifitionTime)
            .LongCountAsync(GetCancellationToken(cancellationToken));
        }
    }
}